package ru.urfc.portal.ui.client.controllers;

import java.util.Date;
import java.util.List;

import ru.urfc.portal.ui.client.Utils;
import ru.urfc.portal.ui.client.controllers.loaders.ConfigurableLoader;
import ru.urfc.portal.ui.client.controllers.loaders.LoaderWithPaging;
import ru.urfc.portal.ui.client.controllers.loaders.LoaderWithPagingListenter;
import ru.urfc.portal.ui.client.descriptor.GridDescriptor;
import ru.urfc.portal.ui.client.descriptor.GridField;
import ru.urfc.portal.ui.client.descriptor.SimpleGridField;
import ru.urfc.portal.ui.client.descriptor.Visitor;
import ru.urfc.portal.ui.client.renderers.ExtFieldRenderer;

import com.extjs.gxt.ui.client.data.BaseModelData;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.EventType;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;

public class ItemsController extends BaseController {

	private Element parent;
	private Element itemTemplate;
	private ModelData modelData = new BaseModelData();
	private LoaderWithPaging loader; 
	
	public ItemsController(GridDescriptor descriptor) {
		this(descriptor, null, null);
	}

	public ItemsController(GridDescriptor descriptor, Element parent, Element itemTemplate) {
		super(descriptor);
		this.parent = parent;
		this.itemTemplate = itemTemplate;
	}

	@Override
	protected ConfigurableLoader<?> createLoader(GridDescriptor descriptor) {
		loader = new LoaderWithPaging(descriptor);
		loader.addLoadListener(new LoaderWithPagingListenter() {
			@Override
			public void onLoad(List<ModelData> data) {
				onUpdate(data);
			}
		});
		return loader;
	}

	public LoaderWithPaging getLoader() {
		return loader;
	}

	protected void onUpdate(List<ModelData> data) {
		for (ModelData modelData: data) {
			this.modelData = modelData;
			for (GridField field: descriptor.getAssignedFields()) {
				field.updateViewFromModel(modelData);
			}
			if (itemTemplate != null && parent != null) {
				NodeList<Node> childNodes = itemTemplate.getChildNodes();
				for (int i = 0; i < childNodes.getLength(); ++i) {
					Node node = childNodes.getItem(i);
					Node clone = node.cloneNode(true);
					parent.appendChild(clone);
				}
			}
		}
	}

	public ModelData getModelData() {
		return modelData;
	}

	public static EventType BEFORE_POST_EVENT = new EventType();
	public static EventType BEFORE_PUT_EVENT = new EventType();
	
	public void doPost() {
		if (validate()) {
			observable.fireEvent(BEFORE_POST_EVENT, new BaseEvent(BEFORE_POST_EVENT));
			super.doPost(generateJson().toString());
		}
	}
	
	public void doPut() {
		if (validate()) {
			observable.fireEvent(BEFORE_PUT_EVENT, new BaseEvent(BEFORE_PUT_EVENT));
			super.doPut(generateJson().toString());
		}
	}
	
	public boolean validate() {
		boolean valid = true;
		for (GridField gridField: descriptor.getEditableFields()) {
			if (gridField.getRenderer() instanceof ExtFieldRenderer) {
				ExtFieldRenderer renderer = gridField.getRenderer();
				valid = valid && renderer.validate();
			}			
		}
		return valid;
	}
	
	JSONObject generateJson() {
		final JSONObject object = createJsonObject();
		for (GridField gridField: descriptor.getEditableFields()) {
			gridField.accept(new Visitor() {
				@Override
				public void visit(SimpleGridField gridField) {
					gridField.updateModelFromView(getModelData());
					String value = gridField.getSerializedValue(getModelData());
					if (value != null) {
						String fieldMap = gridField.getFieldMap();
						JSONString endValue = createJsonString(value.toString());
						if (fieldMap.contains("/")) { //TODO it's for catalog items
							String path1 = fieldMap.split("/")[0];
							String path2 = fieldMap.split("/")[1];
							JSONObject secondObject = object.containsKey(path1)? 
									(JSONObject) object.get(path1): createJsonObject();
							secondObject.put(path2, endValue);
							object.put(path1, secondObject);
						} else {
							object.put(fieldMap, endValue);
						}
					}
				}
			});
		}
		return object;
	}

	JSONObject createJsonObject() {
		return new JSONObject();
	}

	JSONString createJsonString(String value) {
		return new JSONString(value);
	}

	public void prepareFilter(final BaseModelData config) {
		for (GridField gridField: descriptor.getEditableFields()) {
			gridField.accept(new Visitor() {				
				@Override
				public void visit(SimpleGridField gridField) {
					gridField.updateModelFromView(getModelData());
					Object value = gridField.getValue(getModelData());
					if (value != null) {
						if (value instanceof Date) {
							value = Utils.dateToStr((Date) value);
						}
						config.set(gridField.getFieldMap(), value);
					}
				}
			});
		}
	}	

}
